using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using SkinnedModel;
using Primitives3D;
using ConfigReader;
using MorphTarget;
using XNAViewerSample.Physics;

namespace XNAViewerSample
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class ModelsComponent : Microsoft.Xna.Framework.DrawableGameComponent
    {
        #region Fields
        private Dictionary<String, CSkinnedModel> SkinnedModelList;
        private Dictionary<String, CStaticModel> StaticModelList;
        private Dictionary<String, Int16> ModelDrawList;

        private CameraComponent mainCamera;
        private CameraComponent subCamera;
        private Vector3 activeLightPosition;    // deprecated
        private ContentManager contentLoader;

        public enum ModelType { SKINNED, STATIC };
        public bool showSpheres;
        private SpherePrimitive spherePrimitive;
        #endregion

        /// <summary>
        /// Constructor for ModelsComponent class
        /// </summary>
        /// <param name="game"></param>
        public ModelsComponent(Game game)
            : base(game)
        {
            this.DrawOrder = 100;   // ensure other components are drawn first (e.g. skybox)
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            SkinnedModelList = new Dictionary<String, CSkinnedModel>();
            StaticModelList = new Dictionary<String, CStaticModel>();
            ModelDrawList = new Dictionary<String, Int16>();

            showSpheres = false;

            base.Initialize();
        }

        /// <summary>
        /// Public method to access skinned model list
        /// </summary>
        public Dictionary<String, CSkinnedModel> SkinModel
        {
            get { return SkinnedModelList; }
        }

        /// <summary>
        /// Public method to access static model list
        /// </summary>
        public Dictionary<String, CStaticModel> StaticModel
        {
            get { return StaticModelList; }
        }

        public ContentManager ContentLoader
        {
            set { contentLoader = value; }
        }

        /// <summary>
        /// Public method to set the active camera
        /// Only one at a time per model manager
        /// </summary>
        public CameraComponent MainCamera
        {
            set { mainCamera = value; }
        }

        public CameraComponent SubCamera
        {
            set { subCamera = value; }
        }

        /// <summary>
        /// Public method to set the active key light
        /// Depends on Shader implementation
        /// NB: Deprecated
        /// </summary>
        public Vector3 ActiveLightPosition
        {
            set { activeLightPosition = value; }
        }

        /// <summary>
        /// Adds skinned or static model to ModelsComponent manager
        /// </summary>
        /// <param name="Id">String identifier of model</param>
        /// <param name="assetName">Name of content asset</param>
        /// <param name="type">Type of model (SKINNED or STATIC)</param>
        public void Add(String Id, String assetName, ModelType type)
        {
            if (ModelDrawList.ContainsKey(Id)) return;

            if (type == ModelType.SKINNED)
            {
                CSkinnedModel cModel = new CSkinnedModel();
                cModel.ModelInfo = contentLoader.Load<Model>(assetName);
                // skinned model requires a tag info
                if (cModel.TagInfo == null)
                    throw new InvalidOperationException("This model does not contain a SkinningData tag.");
                else
                {
                    //set custom tag info per mesh
                    foreach (ModelMesh mesh in cModel.ModelInfo.Meshes)
                    {
                        CMesh cm = new CMesh();
                        cm.IsVisible = true;
                        cm.DrawOrder = 0;
                        mesh.Tag = cm as CMesh;
                    }

                    // set up an animation container
                    cModel.Animation = new AnimationContainer(Id);

                    SkinnedModelList.Add(Id, cModel);
                    ModelDrawList.Add(Id, 0);   // draworder is 0 upon creation
                }
            }
            else if (type == ModelType.STATIC)
            {
                CStaticModel cModel = new CStaticModel();
                cModel.ModelInfo = contentLoader.Load<Model>(assetName);
                cModel.modelTransform = Matrix.Identity;

                //set custom tag info per mesh
                foreach (ModelMesh mesh in cModel.ModelInfo.Meshes)
                {
                    CMesh cm = new CMesh();
                    cm.IsVisible = true;
                    cm.DrawOrder = 0;
                    mesh.Tag = cm as CMesh;
                }
                StaticModelList.Add(Id, cModel);
                ModelDrawList.Add(Id, 0);   // draworder is 0 upon creation
            }
            else
                throw new InvalidOperationException("Unknown model type.");
        }

        /// <summary>
        /// Removes a model from modelmanager
        /// TODO: how to release specific models loaded in memory
        /// </summary>
        /// <param name="Id">model Identifier</param>
        public void Remove(string Id)
        {
            if (SkinModel.ContainsKey(Id))
            {
                // TODO: free up memory here (model, morphs, animation, textures)
                // for now, just remove from list
                SkinModel.Remove(Id);
            }

            if (StaticModel.ContainsKey(Id))
            {
                // TODO: free up memory here

                StaticModel.Remove(Id);
            }

            // remove from draw list
            if (ModelDrawList.ContainsKey(Id))
                ModelDrawList.Remove(Id);
        }

        /// <summary>
        /// Change mesh visibility tag. Upon creation all mesh are visible.
        /// </summary>
        /// <param name="modelId">Model name</param>
        /// <param name="meshId">Mesh name within model</param>
        /// <param name="visibility">True if visible, false if not</param>
        public void ChangeMeshVisibilityTag(String modelId, String meshId, bool visibility)
        {
            CMesh meshTag = new CMesh();
            if (SkinnedModelList.ContainsKey(modelId))
            {
                foreach (ModelMesh mesh in this.SkinModel[modelId].ModelInfo.Meshes)
                {
                    if (mesh.Name.Contains(meshId))
                    {
                        meshTag = mesh.Tag as CMesh;
                        meshTag.IsVisible = visibility;
                    }
                }
            }
            if (StaticModelList.ContainsKey(modelId))
            {
                foreach (ModelMesh mesh in this.StaticModel[modelId].ModelInfo.Meshes)
                {
                    if (mesh.Name.Contains(meshId))
                    {
                        meshTag = mesh.Tag as CMesh;
                        meshTag.IsVisible = visibility;
                    }
                }
            }
        }

        /// <summary>
        /// Change the draw order tag for the modelId
        /// Default drawOrder value is 0
        /// Models are drawn according to ascending drawOrder value
        ///    or the order they were added to the modelManager
        /// </summary>
        /// <param name="modelId">Model name</param>
        /// <param name="drawOrder">Signed draw order value</param>
        public void ChangeModelOrder(String modelId, Int16 drawOrder)
        {
            CMesh meshTag = new CMesh();

            if (SkinnedModelList.ContainsKey(modelId))
            {
                meshTag = this.SkinModel[modelId].ModelInfo.Meshes[0].Tag as CMesh;
                meshTag.DrawOrder = drawOrder;
            }
            else if (StaticModelList.ContainsKey(modelId))
            {
                meshTag = this.StaticModel[modelId].ModelInfo.Meshes[0].Tag as CMesh;
                meshTag.DrawOrder = drawOrder;
            }
            else
                throw new ArgumentNullException(modelId, "Model not found!");

            // Update ModelDrawList
            ModelDrawList.Remove(modelId);
            ModelDrawList.Add(modelId, drawOrder);
        }

        /// <summary>
        /// Creates an initial model translation/rotation matrix
        /// </summary>
        /// <param name="modelId">Model name</param>
        /// <param name="initMatrix">Transform matrix</param>
        public void InitTransform(String modelId, InitData initData)
        {
            if (SkinnedModelList.ContainsKey(modelId))
            {
                CSkinnedModel mdl = SkinnedModelList[modelId];
                //mdl.Animation.modelTransform = initMatrix;
                mdl.Rotation = initData.Rot;
                mdl.Translation = initData.Pos;
            }
            else if (StaticModelList.ContainsKey(modelId))
            {
                CStaticModel mdl = StaticModelList[modelId];
                //mdl.modelTransform = initMatrix;
                mdl.Rotation = initData.Rot;
                mdl.Translation = initData.Pos;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void AddMorphTarget(String modelID, String assetName)
        {
            List<MorphInfo> miList = contentLoader.Load<List<MorphInfo>>(assetName);
            CSkinnedModel mdl = this.SkinModel[modelID];
            foreach (MorphInfo mi in miList) {
                if (!mdl.MorphTargets.ContainsKey(mi.Mesh))
                {
                    CMorphTarget mt = new CMorphTarget(mdl.ModelInfo.Meshes[mi.Mesh]);
                    mdl.MorphTargets.Add(mi.Mesh, mt);
                }
                mdl.MorphTargets[mi.Mesh].AddMorph(mi);
                if (mi.Name != "Base")
                    mdl.MorphTargets[mi.Mesh].AddPlayer(mi.Name);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="modelID"></param>
        /// <param name="map"></param>
        public void AddVisemeMap(String modelID, int[] map)
        {
            CSkinnedModel mdl = this.SkinModel[modelID];
            map.CopyTo(mdl.VisemeMap, 0);
        }

        public void AddPersonality(String hook, String modelID, string[] kbSet)
        {
            CSkinnedModel mdl = this.SkinModel[modelID];
            try
            {
                if (mdl.Personality == null)
                    mdl.Personality = new Personality();
                mdl.Personality.CreateKnowledgeSet(hook, kbSet);
            }
            catch
            {
                mdl.Personality = null;
            }
        }

        /// <summary>
        /// Adds a collision spheres to skinned model
        /// </summary>
        /// <param name="mdl">Skinned model</param>
        /// <param name="assetName">Collision spheres xml file</param>
        public void AddCollisionSphere(CSkinnedModel mdl, string assetName)
        {
            mdl.SkinnedSpheres = contentLoader.Load<SkinnedSphere[]>(assetName);
            mdl.BoundingSpheres = new BoundingSphere[mdl.SkinnedSpheres.Length];
            if (spherePrimitive == null)
                spherePrimitive = new SpherePrimitive(GraphicsDevice, 1, 12);   // for display
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Update morph target for all skinned models
            foreach (CSkinnedModel mdl in SkinnedModelList.Values)
            {
                if (mdl.MorphTargets.Count > 0)
                {
                    foreach (CMorphTarget morph in mdl.MorphTargets.Values)
                    {
                        morph.Update(gameTime);
                    }
                }
            }

            // Update animation for all skinned models
            foreach (CSkinnedModel mdl in SkinnedModelList.Values)
            {
                if (!String.IsNullOrEmpty(mdl.Parent))
                {
                    if (!String.IsNullOrEmpty(mdl.AttachTo))
                    {
                        Matrix[] bones = this.SkinModel[mdl.Parent].Animation.MainPlayer.PlayerInfo.GetSkinTransforms();
                        mdl.Animation.modelTransform = bones[SkinModel[mdl.Parent].TagInfo.BoneIndices[mdl.AttachTo]];
                    }
                    else
                    {
                        // model is not attached to bone of parent but follows parent transforms
                        mdl.Animation.modelTransform = this.SkinModel[mdl.Parent].Animation.modelTransform;
                    }
                }
                mdl.Animation.Update(gameTime);
            }

            // Update bounding spheres
            UpdateBoundingSpheres(gameTime);

            UpdateSoftBodyDynamics(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="gameTime"></param>
        private void UpdateSoftBodyDynamics(GameTime gameTime)
        {
            foreach (CSkinnedModel mdl in this.SkinModel.Values)
            {
                if (mdl.SoftBodyDynamics != null)
                {
                    Vector3 childVector, boneAxis;
                    float angle = 0.0f;
                    Vector3 scale, translate;
                    Quaternion rotate;
                    Vector3 rotAxis = Vector3.UnitY;        // just some arbitrary initial value
                                                            // to make compiler happy

                    // TODO: optimize, when not enabled
                    foreach (SoftBodyDynamics sbd in mdl.SoftBodyDynamics.Values)
                    {
                        Matrix[] bones = mdl.Animation.MainPlayer.PlayerInfo.GetWorldTransforms();

                        // let PASSIVE bones follow animations/model transforms
                        foreach (SoftBodyBone bone in sbd.SoftBodyObjects)
                        {
                            if ((bone.SBObjectType == SBObjectType.PASSIVE))
                            {
                                bones[bone.boneIndex].Decompose(out scale, out rotate, out translate);
                                bone.CurrPosition = translate;
                                bone.CurrRotation = rotate;
                            }
                        }
                        // update point constraints to follow animation/model transforms
                        foreach (Physics.Constraints c in sbd.Constraints)
                        {
                            if (c is PointConstraint)
                            {
                                PointConstraint pc = c as PointConstraint;
                                SoftBodyBone bone = pc.SbModel as SoftBodyBone;
                                bones[bone.boneIndex].Decompose(out scale, out rotate, out translate);
                                pc.Point = translate;
                                bone.CurrPosition = translate;
                                bone.CurrRotation = rotate;
                            }
                        }
                        // TODO: update non-constant global force generators here, e.g. Wind

                        // call update to perform calculations
                        sbd.Update(gameTime);

                        // do final processing for ACTIVE bones
                        // TODO: do collision check, rotation limits
                        if (sbd.Type == ConfigReader.Physics.PType.HAIR)
                        {
                            // this is a chain of bones, so orient bones to point to immediate child
                            for (int i = 0; i < sbd.SoftBodyObjects.Count - 1; i++)
                            {
                                if (sbd.SoftBodyObjects[i].SBObjectType == SBObjectType.ACTIVE)
                                {
                                    // get direction vector
                                    childVector = sbd.SoftBodyObjects[i + 1].CurrPosition - sbd.SoftBodyObjects[i].CurrPosition;
                                    if (childVector != Vector3.Zero)
                                    {
                                        childVector.Normalize();
                                        // get rotation angle from default bone pose
                                        SoftBodyBone sbb = sbd.SoftBodyObjects[i] as SoftBodyBone;
                                        //sbb.bindTransform.Decompose(out scale, out rotate, out translate);
                                        bones[sbb.boneIndex].Decompose(out scale, out rotate, out translate);

                                        boneAxis = bones[sbb.boneIndex].Left;
                                        boneAxis.Normalize();
                                        angle = (float)Math.Acos(Vector3.Dot(boneAxis, -childVector));
                                        // get axis of rotation
                                        rotAxis = Vector3.Cross(boneAxis, -childVector);
                                        if (rotAxis != Vector3.Zero) rotAxis.Normalize();
                                        // rotate sbb
                                        sbb.CurrRotation = rotate * Quaternion.CreateFromAxisAngle(rotAxis, angle);
                                    }
                                }
                            }
                            // for last segment, just follow orientation of parent segment
                            SoftBodyBone sbLast = sbd.SoftBodyObjects[sbd.SoftBodyObjects.Count - 1] as SoftBodyBone;
                            //sbLast.bindTransform.Decompose(out scale, out rotate, out translate);
                            bones[sbLast.boneIndex].Decompose(out scale, out rotate, out translate);
                            sbLast.CurrRotation = rotate * Quaternion.CreateFromAxisAngle(rotAxis, angle);

                            // apply transform to bones
                            foreach (SoftBodyObjects sb in sbd.SoftBodyObjects)
                            {
                                sb.Update(gameTime, sbd.IsEnabled);   
                            }
                        }
                        if (sbd.Type == ConfigReader.Physics.PType.BREAST)
                        {
                            // this is a chain of bones, so orient bones to point to immediate child
                            for (int i = 0; i < sbd.SoftBodyObjects.Count - 1; i++)
                            {
                                if (sbd.SoftBodyObjects[i].SBObjectType == SBObjectType.ACTIVE)
                                {
                                    // get direction vector
                                    childVector = sbd.SoftBodyObjects[i + 1].CurrPosition - sbd.SoftBodyObjects[i].CurrPosition;
                                    if (childVector != Vector3.Zero)
                                    {
                                        childVector.Normalize();
                                        // get rotation angle from default bone pose
                                        SoftBodyBone sbb = sbd.SoftBodyObjects[i] as SoftBodyBone;
                                        //sbb.bindTransform.Decompose(out scale, out rotate, out translate);
                                        bones[sbb.boneIndex].Decompose(out scale, out rotate, out translate);

                                        // TODO: the way the model was created, breast bones are mirrored
                                        if (i % 2 == 0)
                                            boneAxis = bones[sbb.boneIndex].Left;
                                        else
                                            boneAxis = bones[sbb.boneIndex].Right;
                                        boneAxis.Normalize();
                                        angle = (float)Math.Acos(Vector3.Dot(boneAxis, -childVector));
                                        // get axis of rotation
                                        rotAxis = Vector3.Cross(boneAxis, -childVector);
                                        if (rotAxis != Vector3.Zero) rotAxis.Normalize();
                                        // rotate sbb
                                        sbb.CurrRotation = rotate*Quaternion.CreateFromAxisAngle(rotAxis, angle);
                                    }
                                }
                            }
                            // for last segment, just follow orientation of parent segment
                            SoftBodyBone sbLast = sbd.SoftBodyObjects[sbd.SoftBodyObjects.Count - 1] as SoftBodyBone;
                            //sbLast.bindTransform.Decompose(out scale, out rotate, out translate);
                            bones[sbLast.boneIndex].Decompose(out scale, out rotate, out translate);
                            sbLast.CurrRotation = rotate * Quaternion.CreateFromAxisAngle(rotAxis, angle);

                            // apply transform to bones
                            foreach (SoftBodyObjects sb in sbd.SoftBodyObjects)
                            {
                                sb.Update(gameTime, sbd.IsEnabled);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Updates the boundingSpheres array to match the current animation state.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values (unused)</param>
        private void UpdateBoundingSpheres(GameTime gameTime)
        {
            foreach (CSkinnedModel mdl in SkinnedModelList.Values)
            {
                if (mdl.SkinnedSpheres != null)
                {
                    // Look up the current world space bone positions.
                    Matrix[] worldTransforms = mdl.Animation.Players["Main"].PlayerInfo.GetWorldTransforms();

                    for (int i = 0; i < mdl.SkinnedSpheres.Length; i++)
                    {
                        // Convert the SkinnedSphere description to a BoundingSphere.
                        SkinnedSphere source = mdl.SkinnedSpheres[i];
                        Vector3 center = new Vector3(0, 0, source.Offset);
                        BoundingSphere sphere = new BoundingSphere(center, source.Radius);

                        // Transform the BoundingSphere by its parent bone matrix,
                        // and store the result into the boundingSpheres array.
                        int boneIndex = mdl.TagInfo.BoneIndices[source.BoneName];

                        mdl.BoundingSpheres[i] = sphere.Transform(worldTransforms[boneIndex]);
                    }
                }
            }
        }

        /// <summary>
        /// Allows the game component to draw itself
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values</param>
        public override void Draw(GameTime gameTime)
        {
            // Set the viewport to draw
            //Viewport oldViewport = GraphicsDevice.Viewport;
            //GraphicsDevice.Viewport = mainCamera.CameraViewport;

            //// Dynamically determine the draw order
            // Sort ModelDrawList according to Value

            // Using LINQ
            //var sortedList = (from entry in ModelDrawList orderby entry.Value ascending select entry);

            // OR Using List.Sort
            List<KeyValuePair<string, Int16>> sortedList = new List<KeyValuePair<string, Int16>>(ModelDrawList);
            sortedList.Sort((x, y) => x.Value.CompareTo(y.Value));

            // Then loop thru the entire list to render the models
            mainCamera.Enabled = true;      // do not allow disabling of mainCamera
            DrawModels(sortedList, mainCamera);
            DrawModels(sortedList, subCamera);

            // Draw bounding spheres last
            if (showSpheres)
                DrawBoundingSpheres(mainCamera.ViewMatrix, mainCamera.ProjectionMatrix);

            base.Draw(gameTime);

            // restore viewport
            //GraphicsDevice.Viewport = oldViewport;
        }

        /// <summary>
        /// Draws the models according to draw order
        /// </summary>
        /// <param name="sortedList">Sorted list of models</param>
        /// <param name="camera">Camera that determines view/projection matrices</param>
        private void DrawModels(List<KeyValuePair<string, Int16>> sortedList, CameraComponent camera)
        {
            // return if camera is non-existent or disabled
            if (camera == null) return;
            if (camera.Enabled == false) return;

            // Set the viewport to the camera's viewport
            Viewport oldViewport = GraphicsDevice.Viewport;
            GraphicsDevice.Viewport = camera.Viewport;
            //GraphicsDevice.RasterizerState = Wireframe;
            
            for (int i = 0; i < sortedList.Count; i++)
            {
                String modelId = sortedList.ElementAt(i).Key;

                if (SkinnedModelList.ContainsKey(modelId))
                {
                    CSkinnedModel cmdl = SkinnedModelList[modelId];
                    // get bone transforms
                    Matrix[] bones = cmdl.Animation.Players["Main"].PlayerInfo.GetSkinTransforms();

                    // then render the mesh
                    foreach (ModelMesh mesh in cmdl.ModelInfo.Meshes)
                    {
                        // do not show invisible meshes
                        CMesh meshTag = mesh.Tag as CMesh;
                        if (meshTag.IsVisible == false)
                            continue;
                        foreach (SkinnedEffect effect in mesh.Effects)
                        {
                            effect.EnableDefaultLighting();
                            effect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                            effect.PreferPerPixelLighting = true;

                            // load custom texture here
                            if (meshTag.DefTexture == null)
                                meshTag.DefTexture = effect.Texture;
                            if (meshTag.CustomTexture != null)
                                effect.Texture = meshTag.CustomTexture;
                            else
                                effect.Texture = meshTag.DefTexture;

                            effect.SetBoneTransforms(bones);
                            effect.View = camera.ViewMatrix;
                            effect.Projection = camera.ProjectionMatrix;
                        }
                        mesh.Draw();
                    }
                }
                else if (StaticModelList.ContainsKey(modelId))
                {
                    CStaticModel cmdl = StaticModelList[modelId];
                    Matrix transform;
                    Matrix[] bones;

                    // Find parent bone to attach to
                    if (cmdl.Parent != null)
                        bones = SkinnedModelList[cmdl.Parent].Animation.Players["Main"].PlayerInfo.GetSkinTransforms();
                    else
                        bones = new Matrix[cmdl.ModelInfo.Bones.Count];
                    if (cmdl.AttachTo != null)
                        transform = bones[SkinnedModelList[cmdl.Parent].TagInfo.BoneIndices[cmdl.AttachTo]];
                    else
                        transform = Matrix.Identity * cmdl.modelTransform;
                    // Get mesh transforms
                    bones = new Matrix[cmdl.ModelInfo.Bones.Count];
                    cmdl.ModelInfo.CopyAbsoluteBoneTransformsTo(bones);
                    // then render the mesh
                    foreach (ModelMesh mesh in cmdl.ModelInfo.Meshes)
                    {
                        // do not show invisible meshes
                        CMesh meshTag = mesh.Tag as CMesh;
                        if (meshTag.IsVisible == false)
                            continue;

                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.EnableDefaultLighting();
                            effect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                            effect.PreferPerPixelLighting = true;

                            effect.World = bones[mesh.ParentBone.Index] * transform;
                            effect.View = camera.ViewMatrix;
                            effect.Projection = camera.ProjectionMatrix;
                        }
                        mesh.Draw();
                    }
                }
            }

            // restore viewport
            GraphicsDevice.Viewport = oldViewport;
        }

        /// <summary>
        /// Draws the animated bounding spheres.
        /// </summary>
        void DrawBoundingSpheres(Matrix view, Matrix projection)
        {
            GraphicsDevice.RasterizerState = Wireframe;
            foreach (CSkinnedModel mdl in SkinnedModelList.Values)
            {
                if (mdl.SkinnedSpheres != null)
                {
                    foreach (BoundingSphere sphere in mdl.BoundingSpheres)
                    {
                        Matrix world = Matrix.CreateScale(sphere.Radius) *
                                       Matrix.CreateTranslation(sphere.Center);
                        spherePrimitive.Draw(world, view, projection, Color.White);
                    }
                }
            }
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
        }

        static RasterizerState Wireframe = new RasterizerState
        {
            FillMode = FillMode.WireFrame
        };

    }

}